package framework;

import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.NumberFormat;

import javax.swing.AbstractButton;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFormattedTextField;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListCellRenderer;
import javax.swing.Timer;

/**
 * The controller for display. Controls start/stop/speed/reset of the timer.
 * 
 */
public class DisplayUtilController implements ActionListener {

	// Panel, timer, pluging, other displayutils
	private JPanel buttonPane;
	private Timer timer;
	private JComboBox<Integer> stateList;
	private final static int DELAY_INI = 200;
	private AutomatonPluginInterface automaton;
	private VisualizerPluginInterface visualizer;
	private DisplayUtilStage stage;
	private DisplayUtilMouse mouse;
	private int comboBoxChoice = 0;

	// Button commands
	private final static String BTN_CMD_START = "start";
	private final static String BTN_CMD_SPEED = "speed";
	private final static String BTN_CMD_STOP = "stop";
	private final static String BTN_CMD_RESET = "reset";
	private final static String BTN_CMD_DRAW = "draw";
	private final static String BTN_CMD_CLEAN = "clean";
	private final static String BTN_CMD_OK = "ok";

	// Buttons
	private JButton b1, b2, b3, b4, b5, b6, b7;

	// Text field
	protected JFormattedTextField textField;

	protected Color[] colors;
	protected String[] states;

	/**
	 * Controller that initializes fields.
	 * 
	 * @param JFrame main - the main frame where the display is placed on
	 * @param Timer timer - the timer that controls the periodical update of the display
	 * @param VisualizerPlugin vp -  the visualizer plugin
	 * @param AutomatonPlugin ap - the automaton plugin
	 * @param DisplayUtilStage stage - the stage where the display is shown and managed
	 * @param DisplayUtilMouse mouse - control the mouse actions
	 */
	public DisplayUtilController(JFrame main, Timer timer,
			VisualizerPluginInterface vp, AutomatonPluginInterface ap,
			DisplayUtilStage stage, DisplayUtilMouse mouse) {
		automaton = ap;
		visualizer = vp;
		this.stage = stage;
		this.mouse = mouse;
		buttonPane = new JPanel();
		this.timer = timer;
		states = new String[automaton.getAllStates().length];
		for (int i = 0; i < automaton.getAllStates().length; i++) {
			states[i] = "State " + automaton.getAllStates()[i];
		}
		colors = visualizer.getStateColors();
		addButtons(buttonPane);
		main.add(buttonPane);
	}

	/**
	 * Add buttons to panel
	 * 
	 * @param JPanel p - the panel where the buttons will be added to
	 */
	private void addButtons(JPanel p) {
		// Customize textfield
		textField = new JFormattedTextField(NumberFormat.getNumberInstance());
		textField.setValue(DELAY_INI);
		textField.setColumns(10);
		p.add(textField);

		// Create buttons
		b1 = new JButton(BTN_CMD_SPEED);
		b2 = new JButton(BTN_CMD_START);
		b3 = new JButton(BTN_CMD_STOP);
		b4 = new JButton(BTN_CMD_RESET);
		b5 = new JButton(BTN_CMD_DRAW);

		// Format button positions
		b1.setVerticalTextPosition(AbstractButton.CENTER);
		b1.setHorizontalTextPosition(AbstractButton.CENTER);
		b2.setVerticalTextPosition(AbstractButton.CENTER);
		b2.setHorizontalTextPosition(AbstractButton.CENTER);
		b3.setVerticalTextPosition(AbstractButton.CENTER);
		b3.setHorizontalTextPosition(AbstractButton.CENTER);
		b4.setVerticalTextPosition(AbstractButton.CENTER);
		b4.setHorizontalTextPosition(AbstractButton.CENTER);

		// Initially, disable the stop button.
		b3.setEnabled(false);

		// Add actionListeners to buttons
		b1.addActionListener(this);
		b2.addActionListener(this);
		b3.addActionListener(this);
		b4.addActionListener(this);
		b5.addActionListener(this);

		// Add buttons to panel
		p.add(b1);
		p.add(b2);
		p.add(b3);
		p.add(b4);
		p.add(b5);

		p.revalidate();
		p.repaint();
	}

	/**
	 * Add combo box and buttons to draw mode
	 * 
	 * @param JPanel p - the panel where the buttons and combo box will be added to
	 */
	@SuppressWarnings("unchecked")
	private void addDrawButtons(JPanel p) {
		// Store states as ints
		Integer[] intArray = new Integer[states.length];
		for (int i = 0; i < states.length; i++) {
			intArray[i] = new Integer(i);
		}

		// Create new combo box to allow use to select active state
		stateList = new JComboBox<Integer>(intArray);
		ComboBoxRenderer renderer = new ComboBoxRenderer();
		stateList.setRenderer(renderer);
		stateList.setSelectedIndex(comboBoxChoice);
		// Add actionListener to combo box
		stateList.addActionListener(this);

		// Create buttons for draw mode
		b6 = new JButton(BTN_CMD_CLEAN);
		b7 = new JButton(BTN_CMD_OK);
		// Add actionListeners to buttons
		b6.addActionListener(this);
		b7.addActionListener(this);

		// Add combo box buttons to panel
		p.add(stateList);
		p.add(b6);
		p.add(b7);

		p.revalidate();
		p.repaint();
	}

	
	/**
	 * Handle button pressed events
	 */
	@Override
	public void actionPerformed(ActionEvent e) {
		// If start button pressed
		if (BTN_CMD_START.equals(e.getActionCommand())) {
			int delay = ((Number) textField.getValue()).intValue();
			if (delay > 0) {
				// Set timer delay
				timer.setDelay(delay);
			}
			// Start timer
			timer.start();
			// Enable/disable buttons
			b2.setEnabled(false);
			b5.setEnabled(false);
			b3.setEnabled(true);

		}
		// If speed button pressed
		else if (BTN_CMD_SPEED.equals(e.getActionCommand())) {
			int delay = ((Number) textField.getValue()).intValue();
			if (delay > 0) {
				// Set new timer delay
				timer.setDelay(delay);
			}
		}
		// If stop button pressed
		else if (BTN_CMD_STOP.equals(e.getActionCommand())) {
			// Stop timer
			timer.stop();
			// Enable/disable buttons
			b2.setEnabled(true);
			b5.setEnabled(true);
			b3.setEnabled(false);
		}
		// If reset button pressed
		else if (BTN_CMD_RESET.equals(e.getActionCommand())) {
			// Stop timer
			timer.stop();
			// Clean and set board to initial state
			automaton.getBoard().cleanBoard();
			automaton.getBoard().initBoard();
			// Redraw
			stage.redraw();
			// Enable/disable buttons
			b2.setEnabled(true);
			b5.setEnabled(true);
			b3.setEnabled(false);
		}
		// If draw button pressed
		else if (BTN_CMD_DRAW.equals(e.getActionCommand())) {
			// Remove buttons in run mode and add buttons in draw mode
			buttonPane.removeAll();
			addDrawButtons(buttonPane);
			// Set board to all empty states
			automaton.getBoard().cleanBoard();
			// Redraw
			stage.redraw();
			mouse.setControl(true);
		}
		// If OK button pressed
		else if (BTN_CMD_OK.equals(e.getActionCommand())) {
			// Remove buttons in draw mode and add buttons in run mode
			buttonPane.removeAll();
			addButtons(buttonPane);
			mouse.setControl(false);
		}
		// If clean button pressed
		else if (BTN_CMD_CLEAN.equals(e.getActionCommand())) {
			// Set board to all empty states
			automaton.getBoard().cleanBoard();
			// Redraw
			stage.redraw();
		}
		// If item in combo box selected
		else {
			@SuppressWarnings("unchecked")
			JComboBox<Integer> cb = (JComboBox<Integer>) e.getSource();
			comboBoxChoice = (int) cb.getSelectedItem();
			// Set draw state
			mouse.setDrawState(comboBoxChoice);
		}
	}

	
	/**
	 * This class customizes the combo box
	 * 
	 */
	@SuppressWarnings({ "rawtypes", "serial" })
	class ComboBoxRenderer extends JLabel implements ListCellRenderer {

		public ComboBoxRenderer() {
			setOpaque(true);
			setHorizontalAlignment(CENTER);
			setVerticalAlignment(CENTER);
		}

		
		/**
		 * Configure the combo box items
		 */
		@Override
		public Component getListCellRendererComponent(JList list, Object value,
				int index, boolean isSelected, boolean cellHasFocus) {
			int selectedIndex = ((Integer) value).intValue();
			setBackground(colors[selectedIndex]);
			setText(states[selectedIndex]);
			return this;
		}
	}
}
